package com.yuuzai.openworld.framework.action;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import com.yuuzai.openworld.OpenWorldObject;
import com.yuuzai.openworld.framework.IDescriptor;
import com.yuuzai.openworld.tree.ITreeObject;

public class ActionDesc<IMPL extends Action<?>> extends OpenWorldObject implements IDescriptor<IMPL>, ITreeObject<ActionDesc<IMPL>, ActionDesc<IMPL>> {
	
	@SuppressWarnings("unchecked")
	public IMPL getNextSubAction(Action<?> currentAction) {
		if (currentAction == null) {
			return this.isEmpty() ? null : this.get(0).getNewInstance();
		}
		
		ActionDesc<IMPL> currentDesc = (ActionDesc<IMPL>) currentAction.getDescriptor();
		assertNotNull(currentDesc);
		
		int index = this.indexOf(currentDesc);
		return (index < 0) ? null : this.get(++index).getNewInstance(); 
	}
	
	/* Definition */
	
	private ActionHandler handler;
	
	private String actionLog; 
	
	private ActionDesc<IMPL> parent;
	private List<ActionDesc<IMPL>> children;
	
	public void setHandler(ActionHandler value) {
		this.handler = value;
	}

	public ActionHandler getHandler() {
		return this.handler;
	}

	public void setActionLog(String value) {
		this.actionLog = value;
	}

	public String getActionLog() {
		return this.actionLog;
	}
	
	public ActionDesc() {
		this.setChildren(new ArrayList<ActionDesc<IMPL>>());
	}
	
	/* IDescriptor */
	
	@SuppressWarnings("unchecked")
	public IMPL getNewInstance() {
		Action<ActionDesc<?>> action = new Action<ActionDesc<?>>();
		action.setDescriptor(this);
		return (IMPL) action;
	}

	/* IParentObject */

	public boolean add(ActionDesc<IMPL> e) {
		return children.add(e);
	}

	public void add(int index, ActionDesc<IMPL> element) {
		children.add(index, element);
	}

	public boolean addAll(Collection<? extends ActionDesc<IMPL>> c) {
		return children.addAll(c);
	}

	public boolean addAll(int index, Collection<? extends ActionDesc<IMPL>> c) {
		return children.addAll(index, c);
	}

	public void clear() {
		children.clear();
	}

	public boolean contains(Object o) {
		return children.contains(o);
	}

	public boolean containsAll(Collection<?> c) {
		return children.containsAll(c);
	}

	public ActionDesc<IMPL> get(int index) {
		return (index < 0 || index >= this.size()) ? null : children.get(index);
	}

	public int indexOf(Object o) {
		return children.indexOf(o);
	}

	public boolean isEmpty() {
		return children.isEmpty();
	}

	public Iterator<ActionDesc<IMPL>> iterator() {
		return children.iterator();
	}

	public int lastIndexOf(Object o) {
		return children.lastIndexOf(o);
	}

	public ListIterator<ActionDesc<IMPL>> listIterator() {
		return children.listIterator();
	}

	public ListIterator<ActionDesc<IMPL>> listIterator(int index) {
		return children.listIterator(index);
	}

	public boolean remove(Object o) {
		return children.remove(o);
	}

	public ActionDesc<IMPL> remove(int index) {
		return children.remove(index);
	}

	public boolean removeAll(Collection<?> c) {
		return children.removeAll(c);
	}

	public boolean retainAll(Collection<?> c) {
		return children.retainAll(c);
	}

	public ActionDesc<IMPL> set(int index, ActionDesc<IMPL> element) {
		return children.set(index, element);
	}

	public int size() {
		return children.size();
	}

	public List<ActionDesc<IMPL>> subList(int fromIndex, int toIndex) {
		return children.subList(fromIndex, toIndex);
	}

	public Object[] toArray() {
		return children.toArray();
	}

	public <T> T[] toArray(T[] a) {
		return children.toArray(a);
	}
	
	public void setChildren(List<ActionDesc<IMPL>> value) {
		this.children = value;
		assertNotNull(this.children);
	}

	public List<ActionDesc<IMPL>> getChildren() {
		return Collections.unmodifiableList(this.children);
	}

	/* IChildObject */

	public void setParent(ActionDesc<IMPL> parent) {
		this.parent = parent;
	}

	public ActionDesc<IMPL> getParent() {
		return this.parent;
	}
	
}
